﻿using Engine;
using GameEntitySystem;

namespace Game
{
    public class CommandModLoader : ModLoader 
    {
        public SubsystemCommandDef m_subsystemCommandDef;

        public SubsystemTime m_subsystemTime;

        public override void __ModInitialize()
        {
            ModsManager.RegisterHook("OnProjectLoaded", this);
            ModsManager.RegisterHook("SetRainAndSnowColor", this);
            ModsManager.RegisterHook("ChangeSkyColor", this);
            ModsManager.RegisterHook("ClothingProcessSlotItems", this);
            ModsManager.RegisterHook("OnCapture", this);
            ModsManager.RegisterHook("OnBlockExploded", this);
            ModsManager.RegisterHook("TerrainChangeCell", this);
            ModsManager.RegisterHook("ToFreeChunks", this);
            ModsManager.RegisterHook("ToAllocateChunks", this);
            ModsManager.RegisterHook("SetFurnitureDesignColor", this);
        }

        public override void OnProjectLoaded(Project project)
        {
            m_subsystemCommandDef = project.FindSubsystem<SubsystemCommandDef>();
            m_subsystemTime = project.FindSubsystem<SubsystemTime>();
        }

        public override void ToFreeChunks(TerrainUpdater terrainUpdater, TerrainChunk chunk, out bool KeepWorking)
        {
            KeepWorking = (m_subsystemCommandDef.m_terrainChunks007.Contains(chunk.Coords));
        }

        public override bool ToAllocateChunks(TerrainUpdater terrainUpdater, TerrainUpdater.UpdateLocation[] locations)
        {
            bool result = false;
            foreach (Point2 coord in m_subsystemCommandDef.m_terrainChunks007)
            {
                TerrainChunk chunkAtCoords = terrainUpdater.m_terrain.GetChunkAtCoords(coord.X, coord.Y);
                if (chunkAtCoords == null)
                {
                    result = true;
                    chunkAtCoords = terrainUpdater.m_terrain.AllocateChunk(coord.X, coord.Y);
                    do
                    {
                        terrainUpdater.UpdateChunkSingleStep(chunkAtCoords, terrainUpdater.m_subsystemSky.SkyLightValue);
                    }
                    while (chunkAtCoords.ThreadState < TerrainChunkState.InvalidVertices1);
                }
            }
            return result;
        }

        public override bool SetRainAndSnowColor(ref Color rainColor, ref Color snowColor)
        {
            if(m_subsystemCommandDef.m_rainColor == Color.White)
            {
                return base.SetRainAndSnowColor(ref rainColor, ref snowColor);
            }
            else
            {
                rainColor = m_subsystemCommandDef.m_rainColor;
                snowColor = m_subsystemCommandDef.m_rainColor;
                return true;
            }
        }

        public override Color ChangeSkyColor(Color oldColor, Vector3 direction, float timeOfDay, float precipitationIntensity, int temperature)
        {
            if (m_subsystemCommandDef.m_skyColor == Color.White)
            {
                return base.ChangeSkyColor(oldColor, direction, timeOfDay, precipitationIntensity, temperature);
            }
            else
            {
                return m_subsystemCommandDef.m_skyColor;
            }
        }

        public override bool ClothingProcessSlotItems(ComponentPlayer componentPlayer, Block block, int slotIndex, int value, int count)
        {
            m_subsystemCommandDef.m_eatItem = new Point2(value, count);
            Time.QueueTimeDelayedExecution(Time.RealTime + 0.1f, delegate
            {
                m_subsystemCommandDef.m_eatItem = null;
            });
            return base.ClothingProcessSlotItems(componentPlayer, block, slotIndex, value, count);
        }

        public override void OnCapture()
        {
            m_subsystemCommandDef.m_onCapture = true;
            Time.QueueTimeDelayedExecution(Time.RealTime + 0.1f, delegate 
            {
                m_subsystemCommandDef.m_onCapture = false;
            });
        }

        public override void OnBlockExploded(SubsystemTerrain subsystemTerrain, int x, int y, int z, int value)
        {
            int id = Terrain.ExtractContents(value);
            if (m_subsystemCommandDef.m_firmAllBlocks || m_subsystemCommandDef.m_firmBlockList.Contains(id))
            {
                Time.QueueTimeDelayedExecution(Time.RealTime + 0.05f, delegate
                {
                    subsystemTerrain.ChangeCell(x, y, z, value);
                });
            }
        }

        public override void TerrainChangeCell(SubsystemTerrain subsystemTerrain, int x, int y, int z, int value, out bool Skip)
        {
            if (RecordManager.Recording)
            {
                if(!RecordManager.ChangeBlocks.ContainsKey(new Point3(x, y, z)))
                {
                    RecordManager.ChangeBlocks.Add(new Point3(x, y, z), subsystemTerrain.Terrain.GetCellValue(x, y, z));
                }
                RecordManager.RecordPlayerAction record = new RecordManager.RecordPlayerAction();
                record.ActionName = "Place";
                record.Point = new Point3(x, y, z);
                record.Value = value;
                record.ActionTime = (float)m_subsystemTime.GameTime;
                RecordManager.RecordPlayerActions.Add(record);
            }
            Skip = false;
        }

        public override void SetFurnitureDesignColor(FurnitureDesign design, Block block, int value, ref int FaceTextureSlot, ref Color Color)
        {
            Color newColor = Command.ClayBlock.GetCommandColor(Terrain.ExtractData(value));
            if (!Command.ClayBlock.IsDefaultColor(newColor))
            {
                if (block is Command.ClayBlock || block is LeavesBlock)
                {
                    Color = newColor;
                }
                else if(block is Command.GlassBlock)
                {
                    FaceTextureSlot = 67;
                    Color = newColor;
                }
            }
        }
    }
}